/*
 * Copyright (c) 2000-2005 Apple Computer, Inc. All rights reserved.
 *
 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
 * 
 * This file contains Original Code and/or Modifications of Original Code
 * as defined in and that are subject to the Apple Public Source License
 * Version 2.0 (the 'License'). You may not use this file except in
 * compliance with the License. The rights granted to you under the License
 * may not be used to create, or enable the creation or redistribution of,
 * unlawful or unlicensed copies of an Apple operating system, or to
 * circumvent, violate, or enable the circumvention or violation of, any
 * terms of an Apple operating system software license agreement.
 * 
 * Please obtain a copy of the License at
 * http://www.opensource.apple.com/apsl/ and read it before using this file.
 * 
 * The Original Code and all software distributed under the License are
 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
 * Please see the License for the specific language governing rights and
 * limitations under the License.
 * 
 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
 */
/* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
/*
 * Copyright (c) 1989, 1991, 1993, 1995
 *	The Regents of the University of California.  All rights reserved.
 *
 * This code is derived from software contributed to Berkeley by
 * Rick Macklem at The University of Guelph.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *	This product includes software developed by the University of
 *	California, Berkeley and its contributors.
 * 4. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 */
/*
 * This file includes modifications of code found in the Apple XNU Kernel
 * and has been modifed for use in this Kext by Rick Macklem, May 2006.
 */
#ifndef _NFS_NFSPORT_H_
#define _NFSPORT_NFS_H_

/*
 * In general, I'm not fond of #includes in .h files, but this seems
 * to be the cleanest way to handle #include files for the ports.
 */
#ifndef APPLEKEXT
#include <sys/unistd.h>
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/conf.h>
#include <sys/dir.h>
#include <sys/domain.h>
#include <sys/fcntl.h>
#include <sys/file.h>
#include <sys/filedesc.h>
#include <sys/kernel.h>
#include <sys/lockf.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/mount_internal.h>
#include <sys/namei.h>
#include <sys/proc_internal.h>
#include <sys/protosw.h>
#include <sys/sysproto.h>
#include <sys/reboot.h>
#include <sys/resourcevar.h>
#include <sys/signalvar.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/stat.h>
#include <sys/syslog.h>
#include <sys/time.h>
#include <sys/uio.h>
#include <sys/vnode.h>
#include <sys/vnode_internal.h>
#include <sys/buf.h>
#include <sys/tprintf.h>
#include <sys/uio_internal.h>
#include <sys/kauth.h>
#include <sys/kdebug.h>
#include <sys/ubc.h>
#include <sys/ubc_internal.h>
#include <sys/file_internal.h>
#include <kern/clock.h>
#include <kern/thread.h>
#include <kern/task.h>
#include <libkern/OSAtomic.h>
#include <net/if.h>
#include <net/radix.h>
#include <net/route.h>
#include <netinet/in.h>
#include <netinet/in_pcb.h>
#include <netinet/in_systm.h>
#include <netinet/in_var.h>
#include <netinet/ip.h>
#include <netinet/ip_var.h>
#include <netinet/tcp.h>
#include <netinet/tcp_fsm.h>
#include <netinet/tcp_seq.h>
#include <netinet/tcp_timer.h>
#include <netinet/tcp_var.h>
#include <crypto/des/des.h>
#include <sys/md5.h>
#include <ufs/ufs/quota.h>
#include <ufs/ufs/ufsmount.h>
#include <vfs/vfs_support.h>
/*
 * For Darwin, these functions should be "static" when built in a kext.
 * (This is always defined as nil otherwise.)
 */
#define	APPLESTATIC
#include <newnfs/nfscrypto/nfsdes.h>
#else
#include "nfsdes.h"
#endif	/* APPLEKEXT */

/*
 * These types must be defined before the nfs includes.
 */
#define	NFSSOCKADDR_T	mbuf_t
#define	NFSPROC_T	struct proc
#define	NFSDEV_T	dev_t
#define	NFSSVCARGS	nfssvc_args
#define	NFSACL_T	kauth_acl_t

/*
 * Define this as the type of ni_pathlen in struct nameidata
 */
#define	NFSPATHLEN_T	u_int

/*
 * These should be defined as the types used for the corresponding VOP's
 * argument type.
 */
#define	NFS_ACCESS_ARGS		struct vop_access_args
#define	NFS_OPEN_ARGS		struct vop_open_args
#define	NFS_GETATTR_ARGS	struct vop_getattr_args
#define	NFS_LOOKUP_ARGS		struct vop_lookup_args
#define	NFS_READDIR_ARGS	struct vop_readdir_args

/*
 * Glue for crypto calls.
 */
#define	KEY_T		des_cblock
#define	KEYSCHED_T	des_key_schedule
#define	MACCKSUM(d, c, l, s, i) \
	des_cbc_cksum((des_cblock *)(d), (des_cblock *)(c), (l), (s), \
		(des_cblock *)(i))
#define	KEYSCHED(k, s)	des_set_key((des_cblock *)(k), (s))

/*
 * The des cbc mode call can be done with the newivec NULL, if there is
 * only one contiguous data area.
 */
#define	CBCMODE(i, o, l, s, v, e) \
	nfs_cbc_encrypt((des_cblock *)(i), (o), (l), (s), (des_cblock *)(v), \
		NULL, (e))
#define	CBCMODE_MULTIPLE(i, o, l, s, v, n, e) \
	nfs_cbc_encrypt((des_cblock *)(i), (o), (l), (s), (des_cblock *)(v), \
		(des_cblock *)(n), (e))

/*
 * Client side constants for size of a client idname and lockowner name.
 */
#define	NFSV4CL_CLIDLEN		18
#define	NFSV4CL_LOCKNAMELEN	12

/*
 * Goofy defines to make the vattr structure work.
 */
#define	vattr		vnode_attr
#define	va_size		va_data_size
#define	va_bytes	va_data_alloc
#define	va_atime	va_access_time
#define	va_mtime	va_modify_time
#define	va_ctime	va_change_time

#ifdef APPLEKEXT
#include "rpcv2.h"
#include "nfsproto.h"
#include "nfsdport.h"
#include "nfs.h"
#include "nfsm_subs.h"
#include "nfscl.h"
#include "nfsclstate.h"
#else
#include <newnfs/nfs/rpcv2.h>
#include <newnfs/nfs/nfsproto.h>
#include <newnfs/nfs/nfsdport.h>
#include <newnfs/nfs/nfs.h>
#include <newnfs/nfs/nfsm_subs.h>
#include <newnfs/nfs/nfscl.h>
#include <newnfs/nfs/nfsclstate.h>
#endif	/* APPLEKEXT */

/*
 * NFS mount state flags (nm_state)
 */
#define NFSSTA_LOCKTIMEO	0x00002000  /* experienced a lock req timeout */
#define	NFSSTA_MOUNTED		0x00004000  /* completely mounted */
#define NFSSTA_LOCKSWORK	0x00008000  /* lock ops have worked. */
#define NFSSTA_TIMEO		0x00010000  /* experienced a timeout. */
#define NFSSTA_FORCE		0x00020000  /* doing a forced unmount. */
#define NFSSTA_HASWRITEVERF	0x00040000  /* Has write verifier for V3 */
#define NFSSTA_GOTPATHCONF	0x00080000  /* Got the V3 pathconf info */
#define NFSSTA_GOTFSINFO	0x00100000  /* Got the V3 fsinfo */
#define	NFSSTA_MNTD		0x00200000  /* Mnt server for mnt point */
#define	NFSSTA_SNDLOCK		0x01000000  /* Send socket lock */
#define	NFSSTA_WANTSND		0x02000000  /* Want above */
#define	NFSSTA_RCVLOCK		0x04000000  /* Rcv socket lock */
#define	NFSSTA_WANTRCV		0x08000000  /* Want above */
#define	NFSSTA_WAITAUTH		0x10000000  /* Wait for authentication */
#define	NFSSTA_HASAUTH		0x20000000  /* Has authenticator */
#define	NFSSTA_WANTAUTH		0x40000000  /* Wants an authenticator */
#define	NFSSTA_AUTHERR		0x80000000  /* Authentication error */

/*
 * NFS mount pathconf info flags (nm_fsinfo.pcflags)
 */
#define NFSPCINFO_NOTRUNC		0x01
#define NFSPCINFO_CHOWN_RESTRICTED	0x02
#define NFSPCINFO_CASE_INSENSITIVE	0x04
#define NFSPCINFO_CASE_PRESERVING	0x08

struct nfs_vattr {
	enum vtype	nva_type;	/* vnode type (for create) */
	u_short		nva_mode;	/* files access mode and type */ 
	dev_t		nva_rdev;	/* device the special file represents */
	uid_t		nva_uid;	/* owner user id */
	gid_t		nva_gid;	/* owner group id */
	uint32_t	nva_fsid;	/* file system id (dev for now) */
	uint64_t	nva_nlink;	/* number of references to file */ 
	uint64_t	nva_fileid;	/* file id */
	uint64_t	nva_size;	/* file size in bytes */
	uint64_t	nva_bytes;	/* bytes of disk space held by file */
	uint32_t	nva_blocksize;	/* blocksize preferred for i/o */
	struct timespec	nva_atime;	/* time of last access */
	struct timespec	nva_mtime;	/* time of last modification */
	struct timespec	nva_ctime;	/* time file changed */
};


/*
 * This structure has extra attributes useful to NFSv4 added to it, but
 * is mostly just "struct vattr".
 */
struct nfsvattr {
	struct nfs_vattr na_vattr;
	struct vnode_attr na_va;
	nfsattrbit_t	na_suppattr;
	u_int64_t	na_filesid[2];
	u_int64_t	na_filerev;
	u_int32_t	na_mntonfileno;
	u_int32_t	na_flags;
	u_int32_t	na_gen;
};

/* used by client */
#define	na_type		na_vattr.nva_type
#define	na_mode		na_vattr.nva_mode
#define	na_rdev		na_vattr.nva_rdev
#define	na_uid		na_vattr.nva_uid
#define	na_gid		na_vattr.nva_gid
#define	na_fsid		na_vattr.nva_fsid
#define	na_nlink	na_vattr.nva_nlink
#define	na_fileid	na_vattr.nva_fileid
#define	na_size		na_vattr.nva_size
#define	na_bytes	na_vattr.nva_bytes
#define	na_blocksize	na_vattr.nva_blocksize
#define	na_atime	na_vattr.nva_atime
#define	na_mtime	na_vattr.nva_mtime
#define	na_ctime	na_vattr.nva_ctime

/* user by server, not client */
#define	na_vaflags	na_va.va_vaflags

struct vop_access_args;
struct vop_open_args;
struct vop_getattr_args;
struct vop_lookup_args;
struct vop_readdir_args;
struct fid;
struct export_args;
struct netexport;

#ifdef APPLEKEXT
#include "nfsmount.h"
#include "nfsnode.h"
#include "nfsclient_var.h"
#include "nfsrtt.h"
#include "nfsrvcache.h"
#include "nfsrvstate.h"
#include "xdr_subs.h"
static void *nfsm_dissct(struct nfsrv_descript *, int);
#else
#include <newnfs/nfsclient/nfsmount.h>
#include <newnfs/nfsclient/nfsnode.h>
#include <newnfs/nfs/nfsrtt.h>
#include <newnfs/nfs/nfsrvcache.h>
#include <newnfs/nfs/nfsrvstate.h>
#include <newnfs/nfs/xdr_subs.h>
#include <newnfs/nfs/nfs_var.h>
#endif	/* APPLEKEXT */

/*
 * Now for the macros that do the simple stuff and call the functions
 * for the hard stuff.
 * They use fields in struct nfsrv_descript to handle the mbuf queues.
 * I replaced most of the macro with an inline function, to minimize
 * the machine code. The inline functions in lower case can be called
 * directly, bypassing the macro.
 */
static __inline void *
nfsm_build(struct nfsrv_descript *nd, int siz)
{
	void *retp;
	mbuf_t mb2;
	int error;

	if (siz > (int)mbuf_trailingspace(nd->nd_mb)) {
		error = mbuf_get(MBUF_WAITOK, MBUF_TYPE_DATA, &mb2);
		if (error)
			panic("nfsm_build mbuf_get error %d", error);
		if (siz > (int)mbuf_maxlen(mb2))
			panic("nfsm_build size error");
		error = mbuf_setnext(nd->nd_mb, mb2);
		if (error)
			panic("nfsm_build mbuf_setnext error %d", error);
		nd->nd_mb = mb2;
		nd->nd_bpos = mbuf_data(mb2);
	}
	retp = (void *)(nd->nd_bpos);
	mbuf_setlen(nd->nd_mb, mbuf_len(nd->nd_mb) +  siz);
	nd->nd_bpos += siz;
	return (retp);
}

#define	NFSM_BUILD(a, c, s)	((a) = (c)nfsm_build(nd, (s)))

static __inline void *
nfsm_dissect(struct nfsrv_descript *nd, int siz)
{
	int tt1; 
	void *retp;

	tt1 = ((caddr_t)mbuf_data(nd->nd_md)) + mbuf_len(nd->nd_md) - nd->nd_dpos; 
	if (tt1 >= siz) { 
		retp = (void *)nd->nd_dpos; 
		nd->nd_dpos += siz; 
	} else { 
		retp = nfsm_dissct(nd, siz); 
	}
	return (retp);
}

#define	NFSM_DISSECT(a, c, s) 						\
	do {								\
		(a) = (c)nfsm_dissect(nd, (s));	 			\
		if ((a) == NULL) { 					\
			error = EBADRPC; 				\
			goto nfsmout; 					\
		}							\
	} while (0)
#define	NFSM_DATAP(m, s)	((struct mbuf *)(m))->m_data += (s)

/*
 * This is the header structure used for the lists, etc. (It has the
 * above record in it.
 */
struct nfsrv_stablefirst {
	LIST_HEAD(, nfsrv_stable) nsf_head;	/* Head of nfsrv_stable list */
	time_t		nsf_eograce;	/* Time grace period ends */
	time_t		*nsf_bootvals;	/* Previous boottime values */
	struct fileproc	*nsf_fp;	/* File table pointer */
	u_char		nsf_flags;	/* NFSNSF_ flags */
	struct nfsf_rec	nsf_rec;	/* and above first record */
};
#define	nsf_lease	nsf_rec.lease
#define	nsf_numboots	nsf_rec.numboots

/* NFSNSF_xxx flags */
#define	NFSNSF_UPDATEDONE	0x01
#define	NFSNSF_GRACEOVER	0x02
#define	NFSNSF_NEEDLOCK		0x04
#define	NFSNSF_EXPIREDCLIENT	0x08
#define	NFSNSF_NOOPENS		0x10
#define	NFSNSF_OK		0x20

/*
 * Maximum number of boot times allowed in record. Although there is
 * really no need for a fixed upper bound, this serves as a sanity check
 * for a corrupted file.
 */
#define	NFSNSF_MAXNUMBOOTS	10000

/*
 * This structure defines the other records in the file. The
 * nst_client array is actually the size of the client string name.
 */
struct nfst_rec {
	u_int16_t	len;
	u_char		flag;
	u_char		client[1];
};
/* and the values for flag */
#define	NFSNST_NEWSTATE	0x1
#define	NFSNST_REVOKE		0x2
#define	NFSNST_GOTSTATE		0x4

/*
 * This structure is linked onto nfsrv_stablefirst for the duration of
 * reclaim.
 */
struct nfsrv_stable {
	LIST_ENTRY(nfsrv_stable) nst_list;
	struct nfsclient	*nst_clp;
	struct nfst_rec		nst_rec;
};
#define	nst_timestamp	nst_rec.timestamp
#define	nst_len		nst_rec.len
#define	nst_flag	nst_rec.flag
#define	nst_client	nst_rec.client

/*
 * At some point the server will run out of kernel storage for
 * state structures. For FreeBSD5.2, this results in a panic
 * kmem_map is full. It happens at well over 1000000 opens plus
 * locks on a PIII-800 with 256Mbytes, so that is where I've set
 * the limit. If your server panics due to too many opens/locks,
 * decrease the size of NFSRV_V4STATELIMIT. If you find the server
 * returning NFS4ERR_RESOURCE a lot and have lots of memory, try
 * increasing it.
 * For Darwin, if this value is too large for your system, you will
 * get "panic: zalloc" either during heavy lock allocation or during
 * heavy file system activity after such an NFS lock load.
 * 900,000 seems to be a little too large for a 256Mbyte x86 system.
 */
#define	NFSRV_V4STATELIMIT	600000	/* Max # of Opens + Locks */

/*
 * Define malloc()  and free() as the macros.
 */
#define	malloc(a, b, c)	_MALLOC((a), (b), (c))
#define	free(a, b)	_FREE((a), (b))

/*
 * Macros for handling socket addresses. (Hopefully this makes the code
 * more portable, since I've noticed some 'BSD don't have sockaddrs in
 * mbufs any more.)
 */
#define	NFSSOCKADDR(a, t)	((t)mbuf_data(a))
#define	NFSSOCKADDRALLOC(a)	do {				\
	errno_t __err;						\
	__err = mbuf_get(MBUF_WAITOK, MBUF_TYPE_SONAME, &(a));	\
	if (__err) {						\
		tsleep(&lbolt, PZERO, "nfsgetsock", 0);		\
		(a) = NULL;					\
	}							\
    } while ((a) == NULL)
#define	NFSSOCKADDRSIZE(a, s)	do { 				\
	mbuf_setlen((a), (s));					\
	((struct sockaddr *)mbuf_data(a))->sa_len = (s);	\
    } while (0)
#define	NFSSOCKADDRFREE(a)	mbuf_freem(a)

/*
 * Allocate mbufs. Must succeed and never set the mbuf ptr to NULL.
 */
#define	NFSMGET(m)	do {					\
	errno_t __err;						\
								\
	__err = mbuf_get(MBUF_WAITOK, MBUF_TYPE_DATA, &(m));	\
	if (__err) {						\
		tsleep(&lbolt, PZERO, "nfsmget", 0);		\
		(m) = NULL;					\
	}							\
    } while ((m) == NULL)
#define	NFSMCLGET(m, w)	do {					\
	errno_t __err;						\
								\
	__err = mbuf_getpacket(MBUF_WAITOK, &(m));		\
	if (__err) {						\
		tsleep(&lbolt, PZERO, "nfsmclget", 0);		\
		(m) = NULL;					\
	}							\
    } while ((m) == NULL)
#define	NFSMGETHDR(m)	do {					\
	errno_t __err;						\
								\
	__err = mbuf_gethdr(MBUF_WAITOK, MBUF_TYPE_DATA, &(m));	\
	if (__err) {						\
		tsleep(&lbolt, PZERO, "nfsmget", 0);		\
		(m) = NULL;					\
	}							\
    } while ((m) == NULL)
#define	NFSMCLGETHDR(m, w) do {					\
	errno_t __err;						\
								\
	__err = mbuf_gethdr(MBUF_WAITOK, MBUF_TYPE_DATA, &(m));	\
	if (__err) {						\
		tsleep(&lbolt, PZERO, "nfsmget", 0);		\
		(m) = NULL;					\
	}							\
    } while ((m) == NULL)
#define	NFSMTOD(m, c)	((c)mbuf_data(m))

/*
 * For architectures that don't mind poorly aligned long pointers,
 * define newnfs_realign(), so it becomes a no-op.
 * (If this isn't defined, the variable nfs_realign_count should be
 *  checked to see if realignment is happening frequently. If it is
 *  on an architecture that cares, the ethernet device drivers should
 *  be fixed to avoid it.)
 * I don't know diddly about ppc, but i386 is ok and I hope ppc is, too.
 */
#define	newnfs_realign(m, s)

/*
 * Define this value for waitflag, used when the nfsd calls nfsrvd_rcv().
 * It should be defined in mbuf.h and must be a value different than
 * M_DONTWAIT, M_WAIT, M_TRYWAIT.
 */
#define	M_FROMNFSD	0x100

/*
 * This macro should be defined to disable the higher level network
 * interrupts.
 */
#define	NFSSPLNET	splnet

/*
 * These should be defined as a process or thread structure, as required
 * for signal handling, etc.
 */
#define	NFSPROCCRED(p)	proc_ucred(p)
#define	NFSUIOPROC(u, p)	(u)->uio_procp = (p)
#define	NFSCNPROC(c, p)	(c)->cn_proc = (p)
#define	NFSGETCNPROC(p, c)	(p) = (c)->cn_proc
#define	NFSPROCP(p)	(p)
#define	NFSSCARG(u, f)	((u)->f)

/*
 * Define the hash function.
 */
#define	NFSCNHASH(c, v) do {						\
	int __ii;							\
	char *__cp;							\
	(c)->cn_hash = 0;						\
	for (__cp = (c)->cn_nameptr, __ii = 1; __ii <= (c)->cn_namelen;	\
		__ii++, __cp++)						\
		(c)->cn_hash += (unsigned char)*__cp * __ii;		\
    } while (0)

#define	NFSCNHASHZERO(c)	((c)->cn_hash = 0)

/*
 * Handling credential structures. NFSNEWCRED() actually just adds a
 * reference, so it can be unref'd when replaced.
 */
APPLESTATIC struct ucred *newnfs_creddup(struct ucred *);
#define	NFSNEWCRED(c)	newnfs_creddup(c)
#define	NFSFREECRED(c)	FREE((c), M_TEMP)

/*
 * Define these to use the time of day clock.
 */
#define	NFSGETTIME(t)		microtime(t)
#define	NFSGETNANOTIME(t)	nanotime(t)

/*
 * These macros are defined to initialize and set the timer routine.
 */
#define	NFS_TIMERINIT \
	newnfs_timer(NULL)
void newnfs_timer_funnel __P((void *));
#define	NFS_TIMERSETUP(t, a) \
	timeout(newnfs_timer_funnel, (void *)0, (t))

/*
 * Handle SMP stuff:
 */
#define	NFSGSSHANDLEREQUIRED
#define	NFSGSSHANDLEMUTEX	extern lck_mtx_t *nfs_gss_mutex
#define	NFSGSSHANDLEMUTEXPTR	nfs_gss_mutex
#define	NFSLOCKGSSHANDLE	lck_mtx_lock(nfs_gss_mutex)
#define	NFSUNLOCKGSSHANDLE	lck_mtx_unlock(nfs_gss_mutex)
#define	NFSSOCKMUTEX		extern lck_mtx_t *nfs_sockl_mutex
#define	NFSSOCKMUTEXPTR		nfs_sockl_mutex
#define	NFSLOCKSOCK		lck_mtx_lock(nfs_sockl_mutex)
#define	NFSUNLOCKSOCK		lck_mtx_unlock(nfs_sockl_mutex)
#define	NFSNAMEIDREQUIRED
#define	NFSNAMEIDMUTEX		extern lck_spin_t *nfs_nameid_slock
#define	NFSLOCKNAMEID		lck_spin_lock(nfs_nameid_slock)
#define	NFSUNLOCKNAMEID		lck_spin_unlock(nfs_nameid_slock)
#define	NFSREQSPINLOCK		extern lck_mtx_t *nfs_req_slock
#define	NFSLOCKREQ()		lck_mtx_lock(nfs_req_slock)
#define	NFSUNLOCKREQ()		lck_mtx_unlock(nfs_req_slock)
#define	NFSCACHELOCKREQUIRED
#define	NFSCACHEMUTEX		extern lck_mtx_t *nfs_cache_mutex
#define	NFSCACHEMUTEXPTR	nfs_cache_mutex
#define	NFSLOCKCACHE		lck_mtx_lock(nfs_cache_mutex)
#define	NFSUNLOCKCACHE		lck_mtx_unlock(nfs_cache_mutex)
#define	NFSV4ROOTMUTEXLOCKREQUIRED
#define	NFSV4ROOTLOCKMUTEX	extern lck_mtx_t *nfs_v4root_mutex
#define	NFSV4ROOTLOCKMUTEXPTR	nfs_v4root_mutex
#define	NFSLOCKV4ROOTMUTEX	lck_mtx_lock(nfs_v4root_mutex)
#define	NFSUNLOCKV4ROOTMUTEX	lck_mtx_unlock(nfs_v4root_mutex)
#define	NFSCLSTATEMUTEX		extern lck_mtx_t *nfs_clstate_mutex
#define	NFSCLSTATEMUTEXPTR	nfs_clstate_mutex
#define	NFSLOCKCLSTATE()	lck_mtx_lock(nfs_clstate_mutex)
#define	NFSUNLOCKCLSTATE()	lck_mtx_unlock(nfs_clstate_mutex)
#define	NFSSTATESPINLOCK	extern lck_spin_t *nfs_state_slock
#define	NFSLOCKSTATE		lck_spin_lock(nfs_state_slock)
#define	NFSUNLOCKSTATE		lck_spin_unlock(nfs_state_slock)
#define	NFSGSSCLMUTEX		extern lck_mtx_t *nfs_gsscl_mutex
#define	NFSLOCKGSSCL		lck_mtx_lock(nfs_gsscl_mutex)
#define	NFSUNLOCKGSSCL		lck_mtx_unlock(nfs_gsscl_mutex)
#define	NFSGSSCLHANDLEMUTEX	extern lck_mtx_t *nfs_gssclhandle_mutex
#define NFSGSSCLHANDLEMUTEXPTR	nfs_gssclhandle_mutex
#define	NFSLOCKGSSCLHANDLE	lck_mtx_lock(nfs_gssclhandle_mutex)
#define	NFSUNLOCKGSSCLHANDLE	lck_mtx_unlock(nfs_gssclhandle_mutex)
#define	NFSDLOCKMUTEX		extern lck_mtx_t *newnfsd_mtx
#define	NFSDLOCKMUTEXPTR	newnfsd_mtx
#define	NFSD_LOCK()		lck_mtx_lock(newnfsd_mtx)
#define	NFSD_UNLOCK()		lck_mtx_unlock(newnfsd_mtx)
#define	NFSLOCKNODE(n)
#define	NFSUNLOCKNODE(n)
#define	NFSLOCKMNT(m)
#define	NFSUNLOCKMNT(m)

#define	NFSPROCLISTLOCK()	proc_list_lock()
#define	NFSPROCLISTUNLOCK()	proc_list_unlock()

#define	nfsmsleep(c, l, p, m, t)	msleep((c), (l), (p), (m), (t))

/*
 * These unlock vnodes for VOPs that leave them locked on some BSDen.
 */
#define	NFSRV_CREATE		VOP_CREATE
#define	NFSRV_MKNOD		VOP_MKNOD
#define	NFSRV_MKDIR		VOP_MKDIR
#define	NFSRV_SYMLINK		VOP_SYMLINK
#define	NFSRV_LINK(d, v, c, p)	VOP_LINK((v), (d), (c))
#define	NFSRV_REMOVE		VOP_REMOVE
#define	NFSRV_RMDIR		VOP_RMDIR

/*
 * These macros handle the namei buffer.
 */
#define	NFSNDFREE(n)	\
		FREE_ZONE((n)->ni_cnd.cn_pnbuf, (n)->ni_cnd.cn_pnlen, M_NAMEI)
#define	NFSCNPFREE(c)	FREE_ZONE((c)->cn_pnbuf, (c)->cn_pnlen, M_NAMEI)
#define	NFSCNPALLOC(c, l)	do { \
		MALLOC_ZONE((c)->cn_pnbuf, char *, (l), M_NAMEI, M_WAITOK); \
		(c)->cn_pnlen = (l); \
	} while (0)
#define	NOMACCHECK	0

/*
 * These macros are called at the start and end of operations that
 * might modify the underlying file system.
 */
#define	NFS_STARTWRITE(v, m)
#define	NFS_ENDWRITE(m)

/*
 * Define this to be whatever call checks for Super user with a cred.
 * argument.
 */
#define	NFSSUSER(c)	suser((c), NULL)

/*
 * Define these to test if a vnode ptr is at the root or refers to text.
 */
#define	NFS_VROOT(v)	((v)->v_flag & VROOT)
#define	NFS_VTEXT(v)	((v)->v_flag & VTEXT)

/*
 * Define these to handle the type of va_rdev.
 */
#define	NFSMAKEDEV(m, n)	makedev((m), (n))
#define	NFSMAJOR(d)		major(d)
#define	NFSMINOR(d)		minor(d)

/*
 * Called when a non-directory is removed, to flush the pages from the vm.
 * (For FreeBSD, it just has to return non-zero, so I really dislike the
 *  lint crap in the compiler making me do all this to avoid a warning.)
 */
#define	NFS_PAGERUNCACHE(v)	((v) = (v))

/*
 * Define this to be the macro that returns the minimum size required
 * for a directory entry.
 */
#define	DIRENT_SIZE(dp)		DIRSIZ(dp)

/*
 * Define the random number generator function
 */
#define	arc4random()	random()

/*
 * Define this to whatever does vfs_export_lookup().
 */
struct netcred *nfsdarwin_export_lookup __P((struct mount *, struct netexport *,
	struct sockaddr *));
#define	NFSD_EXPORT_LOOKUP(m, e, n)	nfsdarwin_export_lookup((m), (e), (n))
int nfsdarwin_check_export __P((struct mount *, struct sockaddr *,
	int *, struct ucred **));
#define	VFS_CHECKEXP(m, n, e, c) nfsdarwin_check_export((m), (n), (e), (c))

/*
 * Define whatever it takes to do a vn_rdwr().
 */
#define	NFSD_RDWR(r, v, b, l, o, s, i, c, a, p) \
	vn_rdwr((r), (v), (b), (l), (o), (s), (i), (c), (int *)(a), (p))

/*
 * Define this as whatever function reboots the machine.
 */
#define	NFSD_REBOOT	boot(RB_BOOT, RB_AUTOBOOT, "")

/*
 * NFSD_UPDFILEREV() - updates the file rev and sets the mtime and ctime
 *  to the current clock time, returning the va_filerev and va_Xtime
 *  values.
 */
#define	NFSD_UPDFILEREV(v, a, c, p)	do { \
		struct vattr va; \
		VATTR_NULL(&va); \
		nanotime(&va.va_mtime); \
		(void) VOP_SETATTR((v), &va, (c), (p)); \
		(void) VOP_GETATTR((v), (a), (c), (p)); \
	} while (0)

/*
 * Defined as the VOP_ISLOCKED macro.
 */
#define	NFSVOPISLOCKED(v, p)	(VOP_ISLOCKED(v) == LK_EXCLUSIVE)

/*
 * Increment the fp count.
 */
#define	NFSFPCNT(f)	(f)->f_count++

/*
 * Macros for handling memory for different BSDen.
 * NFSBCOPY(src, dst, len) - copies len bytes, non-overlapping
 * NFSOVBCOPY(src, dst, len) - ditto, but data areas might overlap
 * NFSBCMP(cp1, cp2, len) - compare len bytes, return 0 if same
 * NFSBZERO(cp, len) - set len bytes to 0x0
 */
#define	NFSBCOPY(s, d, l)	bcopy((s), (d), (l))
#define	NFSOVBCOPY(s, d, l)	ovbcopy((s), (d), (l))
#define	NFSBCMP(s, d, l)	bcmp((s), (d), (l))
#define	NFSBZERO(s, l)		bzero((s), (l))

/*
 * Some queue.h files don't have these dfined in them.
 */
#define	SLIST_END(head)		NULL
#define	LIST_END(head)		NULL
#define	TAILQ_END(head)		NULL

/*
 * This must be defined to be a global variable the increments once
 * per second, but never stops or goes backwards, even when a "date"
 * command changes the tod clock. It is used for delta times for
 * leases, etc.
 */
APPLESTATIC int32_t nfsrv_retuptime(void);
#define	NFSD_MONOSEC		nfsrv_retuptime()

/*
 * The B_INVAFTERWRITE flag should be set to whatever is required by the
 * buffer cache code to say "Invalidate the block after it is written back".
 */
#define	B_INVAFTERWRITE	B_INVAL

/*
 * sys/malloc.h needs M_xx added.
 * (Until then, they are defined as M_TEMP.)
 */
#ifndef M_NFSRVDESC
#define M_NFSRVDESC	M_TEMP
#endif
#ifndef M_NFSNFSDDESC
#define M_NFSNFSDDESC	M_TEMP
#endif
#ifndef M_NFSDIROFF
#define M_NFSDIROFF	M_TEMP
#endif
#ifndef M_NFSFH
#define M_NFSFH	M_TEMP
#endif
#ifndef M_NFSRVCACHE
#define	M_NFSRVCACHE	M_TEMP
#endif
#ifndef M_NFSDV4ROOTDIR
#define	M_NFSDV4ROOTDIR	M_TEMP
#endif
#ifndef	M_NFSDCLIENT
#define	M_NFSDCLIENT M_TEMP
#endif
#ifndef	M_NFSDSTATE
#define	M_NFSDSTATE M_TEMP
#endif
#ifndef	M_NFSDLOCK
#define	M_NFSDLOCK M_TEMP
#endif
#ifndef	M_NFSDLOCKFILE
#define	M_NFSDLOCKFILE M_TEMP
#endif
#ifndef	M_NFSSTRING
#define	M_NFSSTRING M_TEMP
#endif
#ifndef	M_NFSUSERGROUP
#define	M_NFSUSERGROUP M_TEMP
#endif
#ifndef M_NFSGSS
#define	M_NFSGSS	M_TEMP
#endif
#ifndef M_NFSGSSHANDLE
#define	M_NFSGSSHANDLE	M_TEMP
#endif
#ifndef M_NFSGSSCLHANDLE
#define	M_NFSGSSCLHANDLE	M_TEMP
#endif
#ifndef M_NFSDREQ
#define	M_NFSDREQ	M_TEMP
#endif
#ifndef M_NFSCLCLIENT
#define	M_NFSCLCLIENT	M_TEMP
#endif
#ifndef M_NFSCLOWNER
#define	M_NFSCLOWNER	M_TEMP
#endif
#ifndef M_NFSCLOPEN
#define	M_NFSCLOPEN	M_TEMP
#endif
#ifndef M_NFSCLLOCKOWNER
#define	M_NFSCLLOCKOWNER M_TEMP
#endif
#ifndef M_NFSCLLOCK
#define	M_NFSCLLOCK	M_TEMP
#endif
#ifndef M_NFSCLDELEG
#define	M_NFSCLDELEG	M_TEMP
#endif
#ifndef M_NFSV4NODE
#define	M_NFSV4NODE	M_TEMP
#endif
#ifndef M_NFSRGSSSEQ
#define	M_NFSRGSSSEQ	M_TEMP
#endif
#ifndef M_NFSRENEWTHREAD
#define	M_NFSRENEWTHREAD	M_TEMP
#endif
#ifndef M_NFSGSSCL
#define	M_NFSGSSCL	M_TEMP
#endif

/*
 * The IO_METASYNC flag should be implemented for local file systems.
 * (Until then, it is nothin at all.)
 */
#ifndef IO_METASYNC
#define IO_METASYNC	0
#endif

/*
 * These macros handle differences in VFS ops.
 */
int nfsdarwin_fhtovp __P((struct mount *, struct fid *, struct sockaddr *,
	struct vnode **, int *, struct ucred **));
#define	NFSD_FHTOVP(e, m, f, n, v, x, c) \
	(e) = nfsdarwin_fhtovp((m), (f), (n), (v), (x), (c))
#define	NFSD_VGET(m, f, v) \
	VFS_VGET((m), (void *)(f), (v))

struct nfsrv_rec {
	STAILQ_ENTRY(nfsrv_rec) nr_link;
	struct sockaddr	*nr_address;
	struct mbuf	*nr_packet;
};

struct nfssvc_sock {
	TAILQ_ENTRY(nfssvc_sock) ns_chain;	/* List of all nfssvc_sock's */
	lck_rw_t	ns_rwlock;		/* lock for most fields */
	socket_t	ns_so;
	mbuf_t		ns_nam;
	mbuf_t		ns_raw;
	mbuf_t		ns_rawend;
	mbuf_t		ns_rec;
	mbuf_t		ns_recend;
	mbuf_t		ns_frag;
	int		ns_flag;
	int		ns_sotype;
	int		ns_cc;
	int		ns_reclen;
	u_long		ns_sref;
	time_t		ns_timestamp;		/* socket timestamp */
	u_int64_t	ns_sockref;
	time_t		ns_tcpconntime;
};

/* Bits for "ns_flag" */
#define	SLP_VALID	0x01
#define	SLP_DOREC	0x02
#define	SLP_NEEDQ	0x04
#define	SLP_DISCONN	0x08
#define	SLP_GETSTREAM	0x10
#define	SLP_LASTFRAG	0x20
#define	SLP_SAMETCPCONN	0x40
#define SLP_ALLFLAGS	0xff

#ifndef _SYS_SYSPROTO_H_
struct nfssvc_args {
	int flag;
	caddr_t argp;
};
#endif

#define	NFSINT_SIGMASK	(sigmask(SIGINT)|sigmask(SIGTERM)|sigmask(SIGKILL)| \
			 sigmask(SIGHUP)|sigmask(SIGQUIT))

#define	NFSSETUPCALL(s, o, r)	do { \
		(o)->so_upcallarg = (caddr_t)(s); \
		(o)->so_upcall = (r); \
		(o)->so_rcv.sb_flags |= SB_UPCALL; \
		(s)->ns_nflag = SLPN_NEEDQ; \
		thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL); \
		(s)->ns_flag = SLP_VALID; \
	} while (0)
#define	NFSINITSLP(s)

/*
 * Macros to switch between kernel and network.
 */
#define	NFSTONETWORK	thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL)
#define	NFSTOKERNEL	thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL)

/*
 * Define PDIRUNLOCK as 0x0, since it isn't used by Darwin.
 */
#define	PDIRUNLOCK	0x0

/*
 * For Darwin, the quota values are already in bytes instead of blocks.
 */
#define	dqb_curblocks	dqb_curbytes
#define	NFSQUOTABLKTOBYTE(q, b)

/*
 * Define this as the largest file size supported. (It should probably
 * be available via a VFS_xxx Op, but it isn't.
 */
#define	NFSRV_MAXFILESIZE	0x100000000ull

/*
 * Set this macro to index() or strchr(), whichever is supported.
 */
#define	STRCHR(s, c)	strchr((s), (c))

/*
 * Set the n_time in the client write rpc, as required.
 */
#define	NFSWRITERPC_SETTIME(w, n, v4)					\
	do {								\
		if (w) {						\
			(n)->n_mtime = (n)->n_vattr.na_vattr.nva_mtime; \
			if (v4)						\
			    (n)->n_change = (n)->n_vattr.na_filerev;	\
		}							\
	} while (0)


/*
 * Fake value, just to make the client work.
 */
#define	NFS_LATTR_NOSHRINK	1

/*
 * Prototype for nfscl_loadattrcache(), since different for darwin.
 */
APPLESTATIC int nfscl_loadattrcache(struct nfsnode *, struct nfsvattr *, struct nfs_vattr *,
    u_int64_t *, int);

/*
 * If the port runs on an SMP box that can enforce Atomic ops with low
 * overheads, define these as atomic increments/decrements. If not,
 * don't worry about it, since these are used for stats that can be
 * "out by one" without disastrous consequences.
 */
#define NFSINCRGLOBAL(a)	OSAddAtomic(1, (SInt32 *)&(a))
#define NFSDECRGLOBAL(a)	OSSubAtomic(1, (SInt32 *)&(a))

/*
 * These macros checks for a field in vattr being set.
 */
#define	NFSATTRISSET(t, v, a)	VATTR_IS_ACTIVE(v, a)

/*
 * Test/set the mount flag to indicate "has write verifier".
 */
#define	NFSHASWRITEVERF(n)	((n)->nm_state & NFSSTA_HASWRITEVERF)
#define	NFSSETWRITEVERF(n)	((n)->nm_state |= NFSSTA_HASWRITEVERF)

#define	NFS_MAXSOCKBUF	(224*1024)

/*
 * Set boottime.
 */
#define	NFSSETBOOTTIME(b) do { (b).tv_sec = boottime_sec(); (b).tv_usec = 0; } while (0)

#undef QUOTA

#define	NFSNOHASH(fhsum) \
	(&newnfsnodehashtbl[(fhsum) & newnfsnodehash])

/*
 * Catch all structure for stuff that the client passes around.
 */
struct nfsattrstuff {
	u_int64_t	xid;
	struct timespec	premtime;
	struct nfsvattr	*vap;
	int		flags;
};

/*
 * Define a "safe" value for DIRBLKSIZ. (directory entries never cross
 * this size boundary. It is defined as 1024 in ufs/ufs/dir.h, but might
 * be smaller elsewhere?
 */
#define	DIRBLKSIZ	512

/*
 * Call the nfscl_getattr() glue routine.
 */
#define	VOP_GETATTR(v, a, c, p)		nfscl_getattr((v), (a), (c), (p))

/*
 * assorted Darwin specific prototypes.
 */
APPLESTATIC int ncl_bind_resv_thread_wake(void);
void unix_syscall_return(int);

/*
 * Try this value for Darwin8.
 */
#define	NFS_DIRBLKSIZ	4096	/* Must be a multiple of DIRBLKSIZ */

#define	NFS_IOSIZE	(256 * 1024)	/* suggested I/O size */

#ifndef IS_VALID_CRED
#define	IS_VALID_CRED(c)	((c) != NOCRED)
#endif	/* no IS_VALID_CRED */

struct user_nfsd_args {
	int	        sock;		/* Socket to serve */
	user_addr_t	name;		/* Client addr for connection based sockets */
	int	        namelen;	/* Length of name */
};

struct user_nfscbd_args {
	int	        sock;		/* Socket to serve */
	user_addr_t	name;		/* Client addr for connection based sockets */
	int	        namelen;	/* Length of name */
	u_short		port;		/* Port# for callback */
};

APPLESTATIC void nfsrvd_slpfree(struct nfssvc_sock *);

/*
 * Manipulate mount flags.
 */
#define	NFSMNT_RDONLY(m)	((m)->mnt_flag & MNT_RDONLY)
#define	NFSHASNFSV3(n)		((n)->nm_flag & NFSMNT_NFSV3)
#define	NFSHASNFSV4(n)		((n)->nm_flag & NFSMNT_NFSV4)
#define	NFSHASNFSV3OR4(n)	((n)->nm_flag & (NFSMNT_NFSV3 | NFSMNT_NFSV4))
#define	NFSHASGOTFSINFO(n)	((n)->nm_flag & NFSMNT_GOTFSINFO)
#define	NFSHASHASSETFSID(n)	((n)->nm_flag & NFSMNT_HASSETFSID)
#define	NFSHASSTRICT3530(n)	((n)->nm_flag & NFSMNT_STRICT3530)
#define	NFSHASINT(n)		((n)->nm_flag & NFSMNT_INT)
#define	NFSHASSOFT(n)		((n)->nm_flag & NFSMNT_SOFT)
#define	NFSHASINTORSOFT(n)	((n)->nm_flag & (NFSMNT_INT | NFSMNT_SOFT))
#define	NFSHASDUMBTIMR(n)	((n)->nm_flag & NFSMNT_DUMBTIMR)
#define	NFSHASNOCONN(n)		((n)->nm_flag & NFSMNT_MNTD)
#define	NFSHASKERB(n)		((n)->nm_flag & NFSMNT_KERB)
#define	NFSHASALLGSSNAME(n)	((n)->nm_flag & NFSMNT_ALLGSSNAME)
#define	NFSHASINTEGRITY(n)	((n)->nm_flag & NFSMNT_INTEGRITY)
#define	NFSHASPRIVACY(n)	((n)->nm_flag & NFSMNT_PRIVACY)
#define	NFSSETHASSETFSID(n)	((n)->nm_flag |= NFSMNT_HASSETFSID)

/* Define the file handle has function */
APPLESTATIC u_long ncl_hash(u_char *, int);

/*
 * Define this to invalidate the attribute cache for the nfs node.
 */
#define	NFSINVALATTRCACHE(n)	((n)->n_attrstamp = 0)

#define	NFS_LEGACYRPC	1

#endif /* _NFSPORT_NFS_H */
